package csel.controller.decoders;

import csel.controller.dispatchers.AbstractDispatcher;
import csel.controller.factories.CommandFactory;
import csel.controller.factories.ModelCommandFactory;
import csel.controller.factories.ViewCommandFactory;
import csel.model.GameCommand;

/**
 * Reasons for Existence: Defines the run() method for listener worker
 * threads</br> Team Members Responsible:</br> Implementation: Nik, Tait</br>
 * Testing: Nik, Tait</br>
 * 
 * @author Nikolas Wolfe
 */
public abstract class EventDecoder implements Runnable
{
	protected ModelCommandFactory modelCommandFactory;
	protected ViewCommandFactory viewCommandFactory;
	protected CommandFactory currentCommandFactory;

	protected AbstractDispatcher modelDispatcher;
	protected AbstractDispatcher viewDispatcher;
	protected AbstractDispatcher currentDispatcher;

	protected GameCommand gameCommand;

	// Worker thread, has the four method calls that make up the decoding process
	public void run()
	{
		synchronized (this)
		{
			try
			{
				this.wait();
				System.out.println("[CONTROLLER] " + toString() + " is awake!");
				while (!Thread.interrupted())
				{
					retrieveCommand();
					parseCommand();
					createCommand();
					sendCommand();
					this.wait();
				}
			} catch (InterruptedException e)
			{
				Thread.currentThread().interrupt();
			}
		}
		System.out.println("The humanity!");
	}
	
	//adds the command to the dispatch queue
	protected void sendCommand() throws InterruptedException
	{
		// export the command to the dispatch queue
		this.currentDispatcher.export(this.gameCommand);
		System.out.println("[CONTROLLER] " + toString() + " thread dispatched " +
			"a command to the model.");
	}

	protected void createCommand()
	{
		this.gameCommand = this.currentCommandFactory.createGameCommand();
	}

	// defer to subclass
	protected abstract void retrieveCommand();

	// defer to subclass
	public abstract void parseCommand() throws InterruptedException;
	
	//simple toString
	public String toString()
	{
		return this.getClass().getSimpleName();
	}
	
	//changes the current variable for factory and dispatchers to model
	protected void setToModel()
	{
		this.currentCommandFactory = this.modelCommandFactory;
		this.currentDispatcher = this.modelDispatcher;
	}
	
	//changes the current variable for factory and dispatchers to view
	protected void setToView()
	{
		this.currentCommandFactory = this.viewCommandFactory;
		this.currentDispatcher = this.viewDispatcher;
	}

}
